-- $LastChangedDate: 2007-04-30 17:24:59 +0200 (Mon, 30 Apr 2007) $
-- $LastChangedRevision: 72 $
-- $LastChangedBy: david $

-- Obtenido de
-- http://www.cmis.brighton.ac.uk/~je/adacraft/appd.htm#d.8

with Ada.Unchecked_Deallocation;
package body List is
   procedure Delete_Item is new Ada.Unchecked_Deallocation (Item_Record, Item_Access);

   function Size (List : List_Type) return Natural is
   begin
      return List.List.Count;
   end Size;

   function First (List : List_Type) return List_Iterator is
   begin
      return (List => List.List, Current => List.List.First);
   end First;

   function Last (List : List_Type) return List_Iterator is
   begin
      return (List => List.List, Current => null);
   end Last;

   function Succ (Iterator : List_Iterator) return List_Iterator is
   begin
      if Iterator.List = null or else Iterator.Current = null then
         raise List_Error;
      else
         return (List => Iterator.List, Current => Iterator.Current.Next);
      end if;
   end Succ;

   function Pred (Iterator : List_Iterator) return List_Iterator is
   begin
      if Iterator.List = null or else
       Iterator.Current = Iterator.List.First then
         raise List_Error;
      elsif Iterator.Current = null then
         return (List => Iterator.List, Current => Iterator.List.Last);
      else
         return (List => Iterator.List, Current => Iterator.Current.Pred);
      end if;
   end Pred;

   function Value (Iterator : List_Iterator) return Item_Type is
   begin
      if Iterator.List = null or else Iterator.Current = null then
         raise List_Error;
      else
         return Iterator.Current.Item;
      end if;
   end Value;

   procedure Delete (Iterator : in List_Iterator) is
                 Item    : Item_Access := Iterator.Current;
   begin
      if Iterator.List = null or else Iterator.Current = null then
         raise List_Error;
      else
         if Iterator.Current.Next = null then
            Iterator.List.Last := Iterator.Current.Pred;
         else
            Iterator.Current.Next.Pred := Iterator.Current.Pred;
         end if;

         if Iterator.Current.Pred = null then
            Iterator.List.First := Iterator.Current.Next;
         else
            Iterator.Current.Pred.Next := Iterator.Current.Next;
         end if;
         Delete_Item (Item);
         Iterator.List.Count := Iterator.List.Count - 1;
      end if;
   end Delete;

   procedure Insert (Iterator : in List_Iterator;
                     Item     : in Item_Type) is
      New_Item : Item_Access;
   begin
      if Iterator.List = null then
         raise List_Error;
      else
         New_Item      := new Item_Record;
         New_Item.Next := Iterator.Current;
         New_Item.Item := Item;

         if Iterator.Current = null then
            New_Item.Pred      := Iterator.List.Last;
            Iterator.List.Last := New_Item;
         else
            New_Item.Pred         := Iterator.Current.Pred;
            Iterator.Current.Pred := New_Item;
         end if;

         if Iterator.Current = Iterator.List.First then
            Iterator.List.First := New_Item;
         else
            New_Item.Pred.Next := New_Item;
         end if;

         Iterator.List.Count := Iterator.List.Count + 1;
      end if;
   end Insert;

   procedure Update (Iterator : in List_Iterator; Item: in Item_Type) is
   begin
      if Iterator.List = null then
         raise List_Error;
      else
         Iterator.Current.Item := Item;
      end if;

   end Update;

   procedure Finalize (Object : in out List_Type) is
      procedure Delete_Header is
         new Ada.Unchecked_Deallocation (List_Header, List_Access);
   begin
      while First(Object) /= Last(Object) loop
         Delete (First(Object));
      end loop;
      Delete_Header (Object.List);
   end Finalize;

end List;
